Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe changes implement post-chat-completion processing for artist creation workflows. When a "create_new_artist" tool completes successfully, the system now automatically copies the conversation room and its messages to the newly created artist's account, then redirects the user to the new space. Changes
Sequence DiagramsequenceDiagram
actor Client
participant Stream as Chat Stream
participant Handler as Chat Completion<br/>Handler
participant Tool as Tool Output
participant RoomSvc as Room Service
participant DB as Database
Client->>Stream: Send chat message
Stream->>Tool: Process tool execution
Tool->>DB: Create new artist account
Tool-->>Stream: Return tool result
Stream->>Handler: onFinish: Call handleChatCompletion()
Handler->>Tool: Extract create_new_artist result
Tool-->>Handler: Return artistAccountId
Handler->>RoomSvc: copyRoom(roomId, artistAccountId)
RoomSvc->>DB: Create new room copy
DB-->>RoomSvc: Return newRoomId
RoomSvc-->>Handler: Return newRoomId
Handler->>DB: copyChatMessages(sourceChatId,<br/>targetChatId: newRoomId)
DB-->>Handler: Messages duplicated
Handler-->>Stream: Return { redirectPath }
Stream->>Stream: Emit data-redirect message
Stream-->>Client: Send redirect response
Client->>Client: Navigate to /chat/newRoomId
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/chat/handleChatCompletion.ts (1)
1-1:⚠️ Potential issue | 🟡 MinorDuplicate
UIMessageimport.
UIMessageis imported on line 1 and again on line 16. Remove the duplicate.🔧 Proposed fix
-import type { UIMessage } from "ai"; import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails"; ... import { copyChatMessages } from "@/lib/chats/copyChatMessages"; import type { CreateNewArtistResult } from "@/lib/mcp/tools/artists/registerCreateNewArtistTool"; -import { getToolOrDynamicToolName, isToolOrDynamicToolUIPart, type UIMessage } from "ai"; +import { getToolOrDynamicToolName, isToolOrDynamicToolUIPart, type UIMessage } from "ai";Keep only the line 16 import that also brings in the helper functions.
Also applies to: 16-16
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/chat/handleChatCompletion.ts` at line 1, There is a duplicate import of UIMessage; remove the standalone import declaration that only imports UIMessage and keep the combined import statement that brings in UIMessage plus the helper functions (the import that also exports the helpers referenced elsewhere in this module), ensuring no other symbols are removed and imports remain used.
🧹 Nitpick comments (1)
lib/mcp/tools/registerRedirectTool.ts (1)
1-32: Consider moving to a domain subfolder for consistency.Per coding guidelines, MCP tool files should be located in
lib/mcp/tools/[domain]/register[ToolName]Tool.ts. This file is at the root oflib/mcp/tools/. Consider moving it to a domain folder likelib/mcp/tools/navigation/registerRedirectTool.tsorlib/mcp/tools/ui/registerRedirectTool.ts.That said, the implementation itself is clean—Zod schema for input validation, proper use of
getToolResultSuccess/getToolResultError, and sensible path validation requiring a leading/.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/mcp/tools/registerRedirectTool.ts` around lines 1 - 32, Move this tool module into a domain-named subfolder under the tools directory (for example a "navigation" or "ui" domain) to match project conventions; keep the exported function registerRedirectTool and the redirectSchema unchanged, update any import/exports or references that point to this file so they use the new module location, and verify tests/builds pick up the new path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/chat/handleChatCompletion.ts`:
- Around line 116-129: The block calling getCreateArtistRoomIds and
copyChatMessages duplicates the synchronous copy in
registerCreateNewArtistTool.ts; decide whether this post-completion copy is a
fallback or the single source of truth and act accordingly: either remove the
duplicate call here and rely on registerCreateNewArtistTool's copy, or keep it
but change the copyChatMessages call to use clearExisting: false (and add a
brief comment above the createArtistRoomIds loop referencing
registerCreateNewArtistTool.ts to explain the intentional redundancy as a
fallback); update references to roomId and responseMessages as needed when
consolidating.
In `@lib/mcp/tools/artists/registerCreateNewArtistTool.ts`:
- Around line 111-119: The MCP tool currently calls copyChatMessages (in
registerCreateNewArtistTool.ts) with clearExisting: true, duplicating work and
risking a race with the copy performed later in handleChatCompletion; remove the
copyChatMessages call and its error branch from the tool so the tool only
returns the newRoomId (and any metadata) and lets handleChatCompletion perform
the single canonical copy using responseMessages. Ensure
registerCreateNewArtistTool.ts no longer references copyResult or
getToolResultError for that copy path and that the returned tool result still
includes newRoomId so handleChatCompletion can detect and perform the copy.
---
Outside diff comments:
In `@lib/chat/handleChatCompletion.ts`:
- Line 1: There is a duplicate import of UIMessage; remove the standalone import
declaration that only imports UIMessage and keep the combined import statement
that brings in UIMessage plus the helper functions (the import that also exports
the helpers referenced elsewhere in this module), ensuring no other symbols are
removed and imports remain used.
---
Nitpick comments:
In `@lib/mcp/tools/registerRedirectTool.ts`:
- Around line 1-32: Move this tool module into a domain-named subfolder under
the tools directory (for example a "navigation" or "ui" domain) to match project
conventions; keep the exported function registerRedirectTool and the
redirectSchema unchanged, update any import/exports or references that point to
this file so they use the new module location, and verify tests/builds pick up
the new path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bdebd082-f559-4aa9-ad86-0165a6ff8d76
⛔ Files ignored due to path filters (4)
lib/chat/toolChains/__tests__/toolChains.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chats/__tests__/copyChatMessages.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chats/__tests__/copyChatMessagesHandler.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**
📒 Files selected for processing (7)
lib/chat/handleChatCompletion.tslib/chat/toolChains/createNewArtistToolChain.tslib/chats/copyChatMessages.tslib/chats/copyChatMessagesHandler.tslib/mcp/tools/artists/registerCreateNewArtistTool.tslib/mcp/tools/index.tslib/mcp/tools/registerRedirectTool.ts
| const copyResult = await copyChatMessages({ | ||
| sourceChatId: active_conversation_id, | ||
| targetChatId: newRoomId, | ||
| clearExisting: true, | ||
| }); | ||
|
|
||
| if (!copyResult.success) { | ||
| return getToolResultError(copyResult.error ?? "Failed to copy artist conversation"); | ||
| } |
There was a problem hiding this comment.
Duplicate copyChatMessages call creates a race condition.
This MCP tool calls copyChatMessages with clearExisting: true here, but handleChatCompletion.ts (lines 116-129) also calls it for the same newRoomId after parsing the tool output. Both use clearExisting: true, which deletes target memories before inserting.
The sequence:
- MCP tool executes → copies messages → returns
newRoomIdin result handleChatCompletionparsesnewRoomIdfrom tool output → copies messages again
At best, this is redundant work. At worst, if timing varies, the second caller could clear messages the first just inserted, then re-copy potentially stale data.
Recommendation: Keep the copy logic in one location only. Since handleChatCompletion already handles post-completion tasks and has full context of responseMessages, consider removing the copyChatMessages call from this MCP tool and relying solely on handleChatCompletion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/mcp/tools/artists/registerCreateNewArtistTool.ts` around lines 111 - 119,
The MCP tool currently calls copyChatMessages (in
registerCreateNewArtistTool.ts) with clearExisting: true, duplicating work and
risking a race with the copy performed later in handleChatCompletion; remove the
copyChatMessages call and its error branch from the tool so the tool only
returns the newRoomId (and any metadata) and lets handleChatCompletion perform
the single canonical copy using responseMessages. Ensure
registerCreateNewArtistTool.ts no longer references copyResult or
getToolResultError for that copy path and that the returned tool result still
includes newRoomId so handleChatCompletion can detect and perform the copy.
There was a problem hiding this comment.
4 issues found across 11 files
Confidence score: 2/5
- High risk: access control is missing in
lib/mcp/tools/artists/registerCreateNewArtistTool.ts, allowing copying messages from rooms the caller may not own - Open redirect risk in
lib/mcp/tools/registerRedirectTool.tsif protocol-relative paths are accepted, which could allow leaving the app - Score is lower because these are concrete, user-impacting security issues (with moderate/high severity) beyond minor style concerns
- Pay close attention to
lib/mcp/tools/artists/registerCreateNewArtistTool.ts,lib/mcp/tools/registerRedirectTool.ts,lib/chats/copyChatMessages.ts,lib/chat/handleChatCompletion.ts- access control, redirect validation, error handling, and duplicate import cleanup.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/chat/handleChatCompletion.ts">
<violation number="1" location="lib/chat/handleChatCompletion.ts:16">
P1: Custom agent: **Enforce Clear Code Style and Maintainability Practices**
Rule 2 (strict TypeScript maintainability) is violated by re-importing `UIMessage` on the new `ai` import line, creating a duplicate import that breaks compilation. Remove the duplicate type specifier from this added import.</violation>
</file>
<file name="lib/mcp/tools/registerRedirectTool.ts">
<violation number="1" location="lib/mcp/tools/registerRedirectTool.ts:25">
P2: Reject protocol-relative paths ("//...") to avoid allowing redirects outside the app when the tool expects a relative in-app path.</violation>
</file>
<file name="lib/mcp/tools/artists/registerCreateNewArtistTool.ts">
<violation number="1" location="lib/mcp/tools/artists/registerCreateNewArtistTool.ts:112">
P1: Validate that active_conversation_id belongs to the resolved account (or the caller has access) before copying messages; otherwise an API caller can copy messages from rooms they don’t own by supplying a different room ID.</violation>
</file>
<file name="lib/chats/copyChatMessages.ts">
<violation number="1" location="lib/chats/copyChatMessages.ts:49">
P2: Handle insertMemories errors so copyChatMessages consistently returns a CopyChatMessagesResult instead of throwing on insert failures.</violation>
</file>
Architecture diagram
sequenceDiagram
participant UI as Client / UI
participant API as Chat Completion Service
participant Tool as Artist MCP Tool
participant Helper as NEW: copyChatMessages (Helper)
participant DB as Supabase / Database
Note over UI,DB: Artist Creation & Server-Side Copy Flow
UI->>API: POST /api/chat
API->>Tool: execute "create_new_artist"
Tool->>DB: createArtistInDb()
Tool->>DB: copyRoom()
Tool->>Helper: NEW: copyChatMessages(source, target)
Helper->>DB: selectMemories(sourceRoom)
DB-->>Helper: source messages
opt clearExisting is true
Helper->>DB: CHANGED: deleteMemories(targetRoom)
end
Helper->>DB: CHANGED: insertMemories(targetRoom, messages)
Helper-->>Tool: success: boolean
Tool-->>API: returns { newRoomId }
Note over API,Tool: Tool Chain Progression
API->>Tool: NEW: execute "redirect" tool (/chat/<newRoomId>)
Tool-->>API: redirect action
Note over API,Helper: Post-Completion Sync
API->>API: getCreateArtistRoomIds(responseMessages)
loop for each newRoomId
API->>Helper: NEW: copyChatMessages (ensure sync)
Helper-->>API: result
end
API-->>UI: response + redirect instruction
UI->>UI: Client-side redirect to new artist room
Note over UI,Helper: Standalone API Endpoint Flow (Refactored)
UI->>API: POST /api/chats/[id]/messages/copy
API->>Helper: CHANGED: use centralized copyChatMessages()
Helper-->>API: result
API-->>UI: 200 OK (success)
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| inputSchema: redirectSchema, | ||
| }, | ||
| async ({ path }: RedirectArgs) => { | ||
| if (!path.startsWith("/")) { |
There was a problem hiding this comment.
P2: Reject protocol-relative paths ("//...") to avoid allowing redirects outside the app when the tool expects a relative in-app path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/mcp/tools/registerRedirectTool.ts, line 25:
<comment>Reject protocol-relative paths ("//...") to avoid allowing redirects outside the app when the tool expects a relative in-app path.</comment>
<file context>
@@ -0,0 +1,32 @@
+ inputSchema: redirectSchema,
+ },
+ async ({ path }: RedirectArgs) => {
+ if (!path.startsWith("/")) {
+ return getToolResultError("Redirect path must start with '/'.");
+ }
</file context>
| } | ||
| } | ||
|
|
||
| const copiedCount = await insertMemories( |
There was a problem hiding this comment.
P2: Handle insertMemories errors so copyChatMessages consistently returns a CopyChatMessagesResult instead of throwing on insert failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chats/copyChatMessages.ts, line 49:
<comment>Handle insertMemories errors so copyChatMessages consistently returns a CopyChatMessagesResult instead of throwing on insert failures.</comment>
<file context>
@@ -0,0 +1,63 @@
+ }
+ }
+
+ const copiedCount = await insertMemories(
+ sourceMemories.map(memory => ({
+ id: generateUUID(),
</file context>
7e203f8 to
cf9f181
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
lib/chat/handleChatCompletion.ts (2)
26-49: SplitgetCreateArtistResultinto scan + parse helpers.This helper now mixes message traversal with dynamic-tool deserialization, which makes malformed-output behavior harder to test. As per coding guidelines,
**/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: "Flag functions longer than 20 lines" and "Keep functions small and focused."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/chat/handleChatCompletion.ts` around lines 26 - 49, The getCreateArtistResult function mixes traversal and parsing—split it into two focused helpers: one scanner (e.g., scanForCreateArtistPart(responseMessages: UIMessage[]): UIPart | null) that iterates responseMessages and message.parts to locate the matching part where getToolOrDynamicToolName(part) === "create_new_artist" and part.state === "output-available", and a parser (e.g., parseCreateArtistResult(part: UIPart): CreateNewArtistResult | null) that handles the two cases: if part.type === "dynamic-tool" read part.output?.content?.[0]?.text and try JSON.parse (return null on parse errors), otherwise return part.output as CreateNewArtistResult; then update getCreateArtistResult to call the scanner and parser and preserve existing behavior (skip malformed outputs and return null if none found).
120-145: Move the artist-room copy/redirect flow into its own helper.This branch adds room cloning, message copying, and redirect selection to an already busy completion handler; extracting it would make the success/failure paths much easier to reason about. As per coding guidelines,
lib/**/*.ts: "Apply Single Responsibility Principle (SRP): one exported function per file; each file should do one thing well" and "Keep functions under 50 lines", and**/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: "Keep functions small and focused."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/chat/handleChatCompletion.ts` around lines 120 - 145, The artist-room cloning/copy/redirect block should be extracted into a small helper to keep handleChatCompletion focused: create a new async function named processArtistRoomCopyAndGetRedirect(roomId: string, responseMessages: MessageType[]) that encapsulates the getCreateArtistResult -> copyRoom -> copyChatMessages logic and returns the redirectPath string | undefined, preserving the same console.error paths on failures; replace the inlined block in handleChatCompletion with a single await call to this helper and return its result (ensuring handleSendEmailToolOutputs(responseMessages) is still awaited afterward); keep the new helper under ~50 lines and only export it if other modules need it.lib/chat/handleChatStream.ts (1)
44-74: Extract theonFinishworkflow into a named helper.This callback now mixes abort handling, response-message selection, completion side effects, redirect emission, finish emission, and credit deduction. As per coding guidelines,
**/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: "Flag functions longer than 20 lines", "Keep functions small and focused", and "Avoid deep nesting (max 3 levels)."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/chat/handleChatStream.ts` around lines 44 - 74, The onFinish callback is too large and should be extracted into a focused named helper: create an async function (e.g., handleOnFinishEvent or finalizeChatStream) that accepts the event plus required locals (writer, body, streamResult, DEFAULT_MODEL) and move the entire callback body into it—preserve the early return when event.isAborted, the assistantMessages selection logic, the call to handleChatCompletion (with body and responseMessages), emitting the redirect via writer.write if redirectPath exists, emitting the finish event with finishReason, and calling handleChatCredits using await streamResult!.usage and body.model ?? DEFAULT_MODEL; then replace the inline onFinish implementation with onFinish: async event => await handleOnFinishEvent(event, writer, body, streamResult). Ensure you keep the same async/await behavior and imports/closures so types and behavior remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/chat/handleChatCompletion.ts`:
- Around line 142-153: The current flow calls
handleSendEmailToolOutputs(responseMessages) before returning redirectPath, so
any exception there causes the outer catch to return {} and drop the successful
redirect; wrap the call to handleSendEmailToolOutputs(responseMessages) in its
own try/catch so email post-processing failures are contained: on error call
sendErrorNotification({ ...body, path: "/api/chat", error: serializeError(err)
}) and console.error the error but do not rethrow—ensure the function still
returns { redirectPath } (and that handleChatStream will emit the redirect) even
if the email step fails; reference handleSendEmailToolOutputs,
sendErrorNotification, serializeError, and redirectPath when making the change.
- Line 19: Create a new utility file exporting the async function
copyChatMessages with the exact signature export async function
copyChatMessages(params: { sourceChatId: string; targetChatId: string;
clearExisting?: boolean; }): Promise<{ success: boolean; error?: string }>, move
the message-copying logic from copyChatMessagesHandler (the API route) into this
function (including loading source/target chats, optional clearing of existing
messages, copying message content/metadata, and error handling), and then update
copyChatMessagesHandler to call and return the result of copyChatMessages so the
handler only delegates to the utility; ensure all referenced symbols used by
handleChatCompletion.ts (import { copyChatMessages } from
"@/lib/chats/copyChatMessages") match the new module export.
In `@lib/chat/handleChatStream.ts`:
- Around line 56-62: The code emits a "data-redirect" stream event from
handleChatStream (writer.write with type "data-redirect" and data.path) but
there is no consumer for it; either remove this emission or implement a
client-side handler that consumes it. To fix: if keeping the feature, add logic
in the client stream message processor (the function that parses/dispatches
server stream messages — e.g., the onStreamMessage/processStreamEvent handler
used by the chat UI) to detect messages with type "data-redirect", read
data.path and perform navigation (router.push/replace or window.location) and
respect transient semantics, plus add unit/integration tests; otherwise remove
the writer.write({type: "data-redirect", ...}) call from handleChatStream to
eliminate dead code. Reference the writer.write call in handleChatStream.ts and
the app's stream message dispatch handler when implementing the consumer.
---
Nitpick comments:
In `@lib/chat/handleChatCompletion.ts`:
- Around line 26-49: The getCreateArtistResult function mixes traversal and
parsing—split it into two focused helpers: one scanner (e.g.,
scanForCreateArtistPart(responseMessages: UIMessage[]): UIPart | null) that
iterates responseMessages and message.parts to locate the matching part where
getToolOrDynamicToolName(part) === "create_new_artist" and part.state ===
"output-available", and a parser (e.g., parseCreateArtistResult(part: UIPart):
CreateNewArtistResult | null) that handles the two cases: if part.type ===
"dynamic-tool" read part.output?.content?.[0]?.text and try JSON.parse (return
null on parse errors), otherwise return part.output as CreateNewArtistResult;
then update getCreateArtistResult to call the scanner and parser and preserve
existing behavior (skip malformed outputs and return null if none found).
- Around line 120-145: The artist-room cloning/copy/redirect block should be
extracted into a small helper to keep handleChatCompletion focused: create a new
async function named processArtistRoomCopyAndGetRedirect(roomId: string,
responseMessages: MessageType[]) that encapsulates the getCreateArtistResult ->
copyRoom -> copyChatMessages logic and returns the redirectPath string |
undefined, preserving the same console.error paths on failures; replace the
inlined block in handleChatCompletion with a single await call to this helper
and return its result (ensuring handleSendEmailToolOutputs(responseMessages) is
still awaited afterward); keep the new helper under ~50 lines and only export it
if other modules need it.
In `@lib/chat/handleChatStream.ts`:
- Around line 44-74: The onFinish callback is too large and should be extracted
into a focused named helper: create an async function (e.g., handleOnFinishEvent
or finalizeChatStream) that accepts the event plus required locals (writer,
body, streamResult, DEFAULT_MODEL) and move the entire callback body into
it—preserve the early return when event.isAborted, the assistantMessages
selection logic, the call to handleChatCompletion (with body and
responseMessages), emitting the redirect via writer.write if redirectPath
exists, emitting the finish event with finishReason, and calling
handleChatCredits using await streamResult!.usage and body.model ??
DEFAULT_MODEL; then replace the inline onFinish implementation with onFinish:
async event => await handleOnFinishEvent(event, writer, body, streamResult).
Ensure you keep the same async/await behavior and imports/closures so types and
behavior remain unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d2a00217-e043-47d2-a1f6-82d6dd3e151f
⛔ Files ignored due to path filters (3)
lib/chat/__tests__/handleChatCompletion.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chat/__tests__/handleChatStream.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**
📒 Files selected for processing (3)
lib/chat/handleChatCompletion.tslib/chat/handleChatStream.tslib/mcp/tools/artists/registerCreateNewArtistTool.ts
✅ Files skipped from review due to trivial changes (1)
- lib/mcp/tools/artists/registerCreateNewArtistTool.ts
lib/chat/handleChatCompletion.ts
Outdated
| import { serializeError } from "@/lib/errors/serializeError"; | ||
| import type { ChatRequestBody } from "./validateChatRequest"; | ||
| import { copyRoom } from "@/lib/rooms/copyRoom"; | ||
| import { copyChatMessages } from "@/lib/chats/copyChatMessages"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether the helper exists at the imported path and whether Vitest resolves tsconfig aliases.
fd -i '^copyChatMessages\.(ts|tsx|js|jsx)$' lib
fd -i 'vitest.config.*' .
fd -i 'vite.config.*' .
rg -n -C2 'copyChatMessages' lib/chat/handleChatCompletion.ts
rg -n 'vite-tsconfig-paths|resolve\.alias|compilerOptions|paths' tsconfig*.json vite.config.* vitest.config.* 2>/dev/null || trueRepository: recoupable/api
Length of output: 603
🏁 Script executed:
#!/bin/bash
# Search for copyChatMessages definition in the entire codebase
rg -l 'copyChatMessages' lib --type ts --type tsx
# Check directory structure
echo "=== lib/chat directory ==="
ls -la lib/chat 2>/dev/null || echo "lib/chat not found"
echo "=== lib/chats directory ==="
ls -la lib/chats 2>/dev/null || echo "lib/chats not found"
# Search for where copyChatMessages is exported/defined
echo "=== Search for copyChatMessages definition ==="
rg 'export.*copyChatMessages|function copyChatMessages|const copyChatMessages' lib --type ts --type tsx
# Check the import path more carefully
echo "=== Check exact import and usage context ==="
rg -B2 -A2 'from.*copyChatMessages' lib --type ts --type tsxRepository: recoupable/api
Length of output: 3513
🏁 Script executed:
#!/bin/bash
# Check what's exported from copyChatMessagesHandler.ts
echo "=== copyChatMessagesHandler.ts content ==="
cat -n lib/chats/copyChatMessagesHandler.ts
# Search for copyChatMessages anywhere in the codebase (using rg without type flags)
echo ""
echo "=== Search for copyChatMessages function name ==="
rg 'copyChatMessages' . --include='*.ts' --include='*.tsx' -B1 -A1Repository: recoupable/api
Length of output: 4279
🏁 Script executed:
#!/bin/bash
# View the entire handleChatCompletion.ts file to see how copyChatMessages is used
cat -n lib/chat/handleChatCompletion.tsRepository: recoupable/api
Length of output: 6347
Create the missing copyChatMessages utility function.
The import on line 19 references @/lib/chats/copyChatMessages, but this file doesn't exist. copyChatMessagesHandler.ts (the API route handler) is a different concern and cannot be used as a drop-in utility.
Create lib/chats/copyChatMessages.ts and export a function with the signature expected by the call on line 126:
export async function copyChatMessages(params: {
sourceChatId: string;
targetChatId: string;
clearExisting?: boolean;
}): Promise<{ success: boolean; error?: string }>Extract the message-copying logic from copyChatMessagesHandler into this utility, then have the handler delegate to it.
🧰 Tools
🪛 GitHub Actions: Unit Tests
[error] 19-19: Vitest failed to load module import. Cannot find module '@/lib/chats/copyChatMessages' imported from '/home/runner/work/api/api/lib/chat/handleChatCompletion.ts'. Vitest suggests using a paths resolver (e.g., vite-tsconfig-paths) or avoiding tsconfig aliases in Vitest config.
🪛 GitHub Check: test
[failure] 19-19: lib/chat/tests/integration/chatEndToEnd.test.ts
Error: Cannot find module '@/lib/chats/copyChatMessages' imported from '/home/runner/work/api/api/lib/chat/handleChatCompletion.ts'.
- If you rely on tsconfig.json's "paths" to resolve modules, please install "vite-tsconfig-paths" plugin to handle module resolution.
- Make sure you don't have relative aliases in your Vitest config. Use absolute paths instead. Read more: https://vitest.dev/guide/common-errors
❯ lib/chat/handleChatCompletion.ts:19:1
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/chat/handleChatCompletion.ts` at line 19, Create a new utility file
exporting the async function copyChatMessages with the exact signature export
async function copyChatMessages(params: { sourceChatId: string; targetChatId:
string; clearExisting?: boolean; }): Promise<{ success: boolean; error?: string
}>, move the message-copying logic from copyChatMessagesHandler (the API route)
into this function (including loading source/target chats, optional clearing of
existing messages, copying message content/metadata, and error handling), and
then update copyChatMessagesHandler to call and return the result of
copyChatMessages so the handler only delegates to the utility; ensure all
referenced symbols used by handleChatCompletion.ts (import { copyChatMessages }
from "@/lib/chats/copyChatMessages") match the new module export.
lib/chat/handleChatCompletion.ts
Outdated
| // Process any email tool outputs | ||
| await handleSendEmailToolOutputs(responseMessages); | ||
|
|
||
| return { redirectPath }; | ||
| } catch (error) { | ||
| sendErrorNotification({ | ||
| ...body, | ||
| path: "/api/chat", | ||
| error: serializeError(error), | ||
| }); | ||
| console.error("Failed to save chat", error); | ||
| return {}; |
There was a problem hiding this comment.
Don't let email post-processing erase a successful redirect.
If the room copy succeeds and handleSendEmailToolOutputs(responseMessages) throws, the outer catch returns {} and handleChatStream never emits redirectPath even though the new artist room already exists. Isolate the email side effect so unrelated failures do not strand the account in the old chat.
💡 Contain the email failure locally
- // Process any email tool outputs
- await handleSendEmailToolOutputs(responseMessages);
+ try {
+ await handleSendEmailToolOutputs(responseMessages);
+ } catch (emailError) {
+ console.error("Failed to process email tool outputs", emailError);
+ sendErrorNotification({
+ ...body,
+ path: "/api/chat",
+ error: serializeError(emailError),
+ });
+ }
return { redirectPath };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/chat/handleChatCompletion.ts` around lines 142 - 153, The current flow
calls handleSendEmailToolOutputs(responseMessages) before returning
redirectPath, so any exception there causes the outer catch to return {} and
drop the successful redirect; wrap the call to
handleSendEmailToolOutputs(responseMessages) in its own try/catch so email
post-processing failures are contained: on error call sendErrorNotification({
...body, path: "/api/chat", error: serializeError(err) }) and console.error the
error but do not rethrow—ensure the function still returns { redirectPath } (and
that handleChatStream will emit the redirect) even if the email step fails;
reference handleSendEmailToolOutputs, sendErrorNotification, serializeError, and
redirectPath when making the change.
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/chats/copyChatMessages.ts">
<violation number="1" location="lib/chats/copyChatMessages.ts:34">
P1: `clearExisting` delete-then-insert is non-atomic and can permanently erase target messages when insert fails.</violation>
<violation number="2" location="lib/chats/copyChatMessages.ts:40">
P2: Catch insert failures in `copyChatMessages` and return an error result instead of throwing.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| } | ||
|
|
||
| if (clearExisting) { | ||
| const deleted = await deleteMemories(targetChatId); |
There was a problem hiding this comment.
P1: clearExisting delete-then-insert is non-atomic and can permanently erase target messages when insert fails.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chats/copyChatMessages.ts, line 34:
<comment>`clearExisting` delete-then-insert is non-atomic and can permanently erase target messages when insert fails.</comment>
<file context>
@@ -0,0 +1,54 @@
+ }
+
+ if (clearExisting) {
+ const deleted = await deleteMemories(targetChatId);
+ if (!deleted) {
+ return { status: "error", error: "Failed to clear target chat messages" };
</file context>
| } | ||
| } | ||
|
|
||
| const copiedCount = await insertMemories( |
There was a problem hiding this comment.
P2: Catch insert failures in copyChatMessages and return an error result instead of throwing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chats/copyChatMessages.ts, line 40:
<comment>Catch insert failures in `copyChatMessages` and return an error result instead of throwing.</comment>
<file context>
@@ -0,0 +1,54 @@
+ }
+ }
+
+ const copiedCount = await insertMemories(
+ sourceMemories.map(memory => ({
+ id: generateUUID(),
</file context>
There was a problem hiding this comment.
2 issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/chat/__tests__/handleChatCompletion.test.ts">
<violation number="1" location="lib/chat/__tests__/handleChatCompletion.test.ts:347">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**
The redirect-flow test was changed to assert unrelated email handling, so the PR’s claimed redirect behavior is no longer exercised by this test. Restore an assertion on the redirect result to prevent normalizing regressions.</violation>
</file>
<file name="lib/chat/handleCreateArtistRedirect.ts">
<violation number="1" location="lib/chat/handleCreateArtistRedirect.ts:42">
P1: Validate that `body.roomId` belongs to the authenticated account before copying; otherwise this flow can copy another account’s chat history when given a foreign room ID.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| }, | ||
| ]; | ||
|
|
||
| await handleChatCompletion(body, responseMessages); |
There was a problem hiding this comment.
P1: Custom agent: Flag AI Slop and Fabricated Changes
The redirect-flow test was changed to assert unrelated email handling, so the PR’s claimed redirect behavior is no longer exercised by this test. Restore an assertion on the redirect result to prevent normalizing regressions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chat/__tests__/handleChatCompletion.test.ts, line 347:
<comment>The redirect-flow test was changed to assert unrelated email handling, so the PR’s claimed redirect behavior is no longer exercised by this test. Restore an assertion on the redirect result to prevent normalizing regressions.</comment>
<file context>
@@ -362,15 +344,9 @@ describe("handleChatCompletion", () => {
];
- const result = await handleChatCompletion(body, responseMessages);
+ await handleChatCompletion(body, responseMessages);
- expect(mockCopyRoom).toHaveBeenCalledWith("room-456", "artist-123");
</file context>
| return undefined; | ||
| } | ||
|
|
||
| const newRoomId = await copyRoom(body.roomId ?? "", createArtistResult.artistAccountId); |
There was a problem hiding this comment.
P1: Validate that body.roomId belongs to the authenticated account before copying; otherwise this flow can copy another account’s chat history when given a foreign room ID.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chat/handleCreateArtistRedirect.ts, line 42:
<comment>Validate that `body.roomId` belongs to the authenticated account before copying; otherwise this flow can copy another account’s chat history when given a foreign room ID.</comment>
<file context>
@@ -0,0 +1,59 @@
+ return undefined;
+ }
+
+ const newRoomId = await copyRoom(body.roomId ?? "", createArtistResult.artistAccountId);
+ if (!newRoomId) {
+ console.error("Failed to create final artist conversation room");
</file context>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
lib/chat/handleChatStream.ts (1)
32-35: Extract the finish pipeline out ofhandleChatStream().This function now owns request validation, agent setup, stream merging, message persistence, redirect hooks, manual finish emission, and credits. Pull the custom
onFinishbody into a dedicated helper so the control flow stays smaller and the error paths are easier to test.As per coding guidelines,
**/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: Flag functions longer than 20 lines or classes with >200 lines; Keep functions small and focusedAlso applies to: 54-80
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/chat/handleChatStream.ts` around lines 32 - 35, The finish pipeline inside handleChatStream is too large and should be extracted into a dedicated helper to simplify control flow and make error paths testable: create a new function (e.g., finalizeChatStream or handleChatFinish) that encapsulates the current onFinish body and all finish-related responsibilities (stream merging, message persistence, redirect hooks, manual finish emission, credits update, and any error handling), accept the minimal required inputs (request context, agent/result objects, and onFinish callback) and return a normalized result or throw; then replace the inline finish logic in handleChatStream with a single call to this new helper, update tests to call the helper directly for finish-path coverage, and ensure exported types/signatures (handleChatStream, onFinish) remain compatible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/chat/handleChatStream.ts`:
- Around line 55-79: The callback passed to streamResult.toUIMessageStream (the
onFinish handler) currently performs side effects (calling handleChatCompletion,
onFinish hook, writer.write with type "finish", and handleChatCredits) without a
finally, so exceptions can skip emitting the manual finish chunk; refactor the
onFinish async handler to perform the side effects (await handleChatCompletion
and await onFinish) inside a try block and ensure the writer.write({type:
"finish", finishReason: ...}) and the handleChatCredits call run in a finally
block (still awaiting any necessary promises) so the finish chunk is always
emitted even if handleChatCompletion or onFinish throws.
In `@lib/chat/handleCreateArtistRedirect.ts`:
- Around line 42-55: The code creates a new room via copyRoom(...) and then
calls copyChatMessages(...); if copyChatMessages fails the function logs and
returns, leaving the created room behind—fix by deleting the newly created room
on any copy failure (e.g., call a teardown like deleteRoom(newRoomId) or
removeRoom(newRoomId) immediately before returning undefined) or refactor into a
single helper (e.g., createRoomWithHistory or copyRoomAndMessages) that creates
the room and copies history atomically so failures roll back; ensure you
reference copyRoom, newRoomId and copyChatMessages when adding the rollback or
the new atomic helper.
In `@lib/chats/copyChatMessages.ts`:
- Around line 33-53: The clear-and-copy flow can leave the target empty if
insertMemories fails or inserts fewer rows than sourceMemories; update this by
performing delete+insert atomically or validating row counts: create a new
Supabase helper in lib/supabase (e.g., a transactional function for the chat
messages table) that accepts targetChatId and an array of new rows (use
generateUUID() for ids and preserve memory.updated_at/content), run the delete
and bulk insert inside a single transaction, and return success only if the
inserted row count equals sourceMemories.length; alternatively, if you can't use
a DB transaction, at minimum check copiedCount against sourceMemories.length and
return an error when they differ and move all Supabase calls
(deleteMemories/insertMemories) into lib/supabase/[table]/[function].ts.
---
Nitpick comments:
In `@lib/chat/handleChatStream.ts`:
- Around line 32-35: The finish pipeline inside handleChatStream is too large
and should be extracted into a dedicated helper to simplify control flow and
make error paths testable: create a new function (e.g., finalizeChatStream or
handleChatFinish) that encapsulates the current onFinish body and all
finish-related responsibilities (stream merging, message persistence, redirect
hooks, manual finish emission, credits update, and any error handling), accept
the minimal required inputs (request context, agent/result objects, and onFinish
callback) and return a normalized result or throw; then replace the inline
finish logic in handleChatStream with a single call to this new helper, update
tests to call the helper directly for finish-path coverage, and ensure exported
types/signatures (handleChatStream, onFinish) remain compatible.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0acb0b5d-510e-4806-a10b-ba5a9b6866b6
⛔ Files ignored due to path filters (4)
lib/chat/__tests__/handleChatCompletion.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chat/__tests__/handleChatStream.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chat/__tests__/handleCreateArtistRedirect.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chats/__tests__/copyChatMessagesHandler.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**
📒 Files selected for processing (5)
app/api/chat/route.tslib/chat/handleChatStream.tslib/chat/handleCreateArtistRedirect.tslib/chats/copyChatMessages.tslib/chats/copyChatMessagesHandler.ts
| streamResult.toUIMessageStream({ | ||
| sendFinish: false, | ||
| onFinish: async event => { | ||
| if (event.isAborted) { | ||
| return; | ||
| } | ||
|
|
||
| const assistantMessages = event.messages.filter( | ||
| message => message.role === "assistant", | ||
| ); | ||
| const responseMessages = | ||
| assistantMessages.length > 0 ? assistantMessages : [event.responseMessage]; | ||
| await handleChatCompletion(body, responseMessages); | ||
| await onFinish?.({ body, responseMessages, writer }); | ||
|
|
||
| writer.write({ | ||
| type: "finish", | ||
| finishReason: event.finishReason, | ||
| }); | ||
|
|
||
| await handleChatCredits({ | ||
| usage: await streamResult!.usage, | ||
| model: body.model ?? DEFAULT_MODEL, | ||
| accountId: body.accountId, | ||
| }); |
There was a problem hiding this comment.
Always emit the manual finish chunk from a finally.
With sendFinish: false, this callback is now responsible for closing the stream. Any rejection from handleChatCompletion() or the injected onFinish hook skips the finish write, which can leave the client waiting indefinitely. Put the side effects behind a try/finally so finish is sent even when the redirect flow fails.
Possible fix
const responseMessages =
assistantMessages.length > 0 ? assistantMessages : [event.responseMessage];
- await handleChatCompletion(body, responseMessages);
- await onFinish?.({ body, responseMessages, writer });
-
- writer.write({
- type: "finish",
- finishReason: event.finishReason,
- });
+ try {
+ await handleChatCompletion(body, responseMessages);
+ await onFinish?.({ body, responseMessages, writer });
+ } catch (error) {
+ console.error("/api/chat onFinish error:", error);
+ } finally {
+ writer.write({
+ type: "finish",
+ finishReason: event.finishReason,
+ });
+ }
await handleChatCredits({📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| streamResult.toUIMessageStream({ | |
| sendFinish: false, | |
| onFinish: async event => { | |
| if (event.isAborted) { | |
| return; | |
| } | |
| const assistantMessages = event.messages.filter( | |
| message => message.role === "assistant", | |
| ); | |
| const responseMessages = | |
| assistantMessages.length > 0 ? assistantMessages : [event.responseMessage]; | |
| await handleChatCompletion(body, responseMessages); | |
| await onFinish?.({ body, responseMessages, writer }); | |
| writer.write({ | |
| type: "finish", | |
| finishReason: event.finishReason, | |
| }); | |
| await handleChatCredits({ | |
| usage: await streamResult!.usage, | |
| model: body.model ?? DEFAULT_MODEL, | |
| accountId: body.accountId, | |
| }); | |
| streamResult.toUIMessageStream({ | |
| sendFinish: false, | |
| onFinish: async event => { | |
| if (event.isAborted) { | |
| return; | |
| } | |
| const assistantMessages = event.messages.filter( | |
| message => message.role === "assistant", | |
| ); | |
| const responseMessages = | |
| assistantMessages.length > 0 ? assistantMessages : [event.responseMessage]; | |
| try { | |
| await handleChatCompletion(body, responseMessages); | |
| await onFinish?.({ body, responseMessages, writer }); | |
| } catch (error) { | |
| console.error("/api/chat onFinish error:", error); | |
| } finally { | |
| writer.write({ | |
| type: "finish", | |
| finishReason: event.finishReason, | |
| }); | |
| } | |
| await handleChatCredits({ | |
| usage: await streamResult!.usage, | |
| model: body.model ?? DEFAULT_MODEL, | |
| accountId: body.accountId, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/chat/handleChatStream.ts` around lines 55 - 79, The callback passed to
streamResult.toUIMessageStream (the onFinish handler) currently performs side
effects (calling handleChatCompletion, onFinish hook, writer.write with type
"finish", and handleChatCredits) without a finally, so exceptions can skip
emitting the manual finish chunk; refactor the onFinish async handler to perform
the side effects (await handleChatCompletion and await onFinish) inside a try
block and ensure the writer.write({type: "finish", finishReason: ...}) and the
handleChatCredits call run in a finally block (still awaiting any necessary
promises) so the finish chunk is always emitted even if handleChatCompletion or
onFinish throws.
| const newRoomId = await copyRoom(body.roomId ?? "", createArtistResult.artistAccountId); | ||
| if (!newRoomId) { | ||
| console.error("Failed to create final artist conversation room"); | ||
| return undefined; | ||
| } | ||
|
|
||
| const copyResult = await copyChatMessages({ | ||
| sourceChatId: body.roomId ?? "", | ||
| targetChatId: newRoomId, | ||
| clearExisting: true, | ||
| }); | ||
| if (copyResult.status === "error") { | ||
| console.error(copyResult.error); | ||
| return undefined; |
There was a problem hiding this comment.
Roll back the new room when the copy step fails.
copyRoom() has already created the destination room before copyChatMessages() runs. If the copy fails, this path only logs and returns undefined, leaving an empty artist chat behind. Please delete the new room on failure, or combine room creation and history copy into one helper that succeeds atomically.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/chat/handleCreateArtistRedirect.ts` around lines 42 - 55, The code
creates a new room via copyRoom(...) and then calls copyChatMessages(...); if
copyChatMessages fails the function logs and returns, leaving the created room
behind—fix by deleting the newly created room on any copy failure (e.g., call a
teardown like deleteRoom(newRoomId) or removeRoom(newRoomId) immediately before
returning undefined) or refactor into a single helper (e.g.,
createRoomWithHistory or copyRoomAndMessages) that creates the room and copies
history atomically so failures roll back; ensure you reference copyRoom,
newRoomId and copyChatMessages when adding the rollback or the new atomic
helper.
| if (clearExisting) { | ||
| const deleted = await deleteMemories(targetChatId); | ||
| if (!deleted) { | ||
| return { status: "error", error: "Failed to clear target chat messages" }; | ||
| } | ||
| } | ||
|
|
||
| const copiedCount = await insertMemories( | ||
| sourceMemories.map(memory => ({ | ||
| id: generateUUID(), | ||
| room_id: targetChatId, | ||
| content: memory.content, | ||
| updated_at: memory.updated_at, | ||
| })), | ||
| ); | ||
|
|
||
| return { | ||
| status: "success", | ||
| copiedCount, | ||
| clearedExisting: clearExisting, | ||
| }; |
There was a problem hiding this comment.
Make the clear-and-copy step atomic.
deleteMemories() runs before the insert, and insertMemories() only gives you a row count. If the insert fails after the delete, or inserts fewer rows than sourceMemories.length, this helper can empty the target chat and still return status: "success". Please move the delete+insert into a single transactional Supabase function, or at least fail when the inserted count does not match the source count.
As per coding guidelines, lib/!(supabase)/**/*.{ts,tsx}: all Supabase database calls must be in lib/supabase/[table_name]/[function].ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/chats/copyChatMessages.ts` around lines 33 - 53, The clear-and-copy flow
can leave the target empty if insertMemories fails or inserts fewer rows than
sourceMemories; update this by performing delete+insert atomically or validating
row counts: create a new Supabase helper in lib/supabase (e.g., a transactional
function for the chat messages table) that accepts targetChatId and an array of
new rows (use generateUUID() for ids and preserve memory.updated_at/content),
run the delete and bulk insert inside a single transaction, and return success
only if the inserted row count equals sourceMemories.length; alternatively, if
you can't use a DB transaction, at minimum check copiedCount against
sourceMemories.length and return an error when they differ and move all Supabase
calls (deleteMemories/insertMemories) into lib/supabase/[table]/[function].ts.
Summary
Testing
Summary by cubic
Moves the artist handoff fully to the server and finalizes it after chat completion. When
create_new_artistruns, the server creates a new room, copies the chat, and streams a redirect to the new room before sending the final finish.New Features
handleCreateArtistRedirectto parsecreate_new_artist(tool or dynamic-tool), runcopyRoom+copyChatMessages, and return a redirect path.handleChatStreamnow accepts an optional finish callback; it setssendFinish: false, emitsdata-redirect, then writes the finalfinish. The chat API wires this up.Refactors
copyChatMessagesand updated the copy messages API handler to use it.newRoomIdfromregisterCreateNewArtistTool; it now returns onlyartistAccountId.Written for commit e3d8ab6. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes